﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Shared
{
    public class DataPacket : PacketBase
    {
        #region Fields

        private BinaryReader MemoryReader;
        public int ReceiveSize = 0;

        public override byte[] Buffer
        {
            get
            {
                return base.Buffer;
            }
            set
            {
                this.MemoryBuffer.Seek(0, SeekOrigin.Begin);
                this.MemoryBuffer.Write(value, 0, value.Length);
            }
        }

        #endregion

        #region Constructors

        public DataPacket()
        {
            this.MemoryBuffer = new MemoryStream(1452);
            this.MemoryReader = new BinaryReader(MemoryBuffer);
        }

        #endregion

        #region Methods

        public static DataPacket[] SplitNaglePackets(byte[] Buffer)
        {
            BinaryReader BufferReader = new BinaryReader(new MemoryStream(Buffer));
            List<DataPacket> Packets = new List<DataPacket>();

            int BufferSize = Buffer.Length;
            int Offset = 0;

            int CurrentSize;
            int CurrentCount;
            byte[] CurrentBuffer;

            while (true)
            {
                BufferReader.BaseStream.Position = Offset;

                BufferReader.ReadByte();
                BufferReader.ReadInt32();

                CurrentSize = BufferReader.ReadInt32();
                if (CurrentSize == 0)
                {
                    break;
                }

                CurrentCount = 13 + CurrentSize;
                CurrentBuffer = new Byte[CurrentCount];

                Array.Copy(Buffer, Offset, CurrentBuffer, 0, CurrentCount);

                DataPacket Packet = new DataPacket();
                Packet.Buffer = CurrentBuffer;

                Packets.Add(Packet);
                Offset += CurrentCount;
            }

            return Packets.ToArray();
        }

        public static DataPacket[] SplitNaglePackets(DataPacket Packet)
        {
            return SplitNaglePackets(Packet.Buffer);
        }

        public bool VerifyHeaders(int SessionKey)
        {
            CRC32 CRC = new CRC32();

            int DataSize = this.Size - 13;
            int CalculatedLengthHash = ~(BitConverter.ToInt32(CRC.ComputeHash(BitConverter.GetBytes(DataSize)), 0) ^ SessionKey);
            byte[] Data = new byte[DataSize];

            Array.Copy(this.Buffer, 13, Data, 0, DataSize);

            int CalculatedDataHash = ~(BitConverter.ToInt32(CRC.ComputeHash(Data), 0) ^ SessionKey);
            int OldPointer = this.Pointer;
            Pointer = 0;

            if (ReadByte() != 0x5E)
            {
                return false;
            }

            int ReadLengthHash = ReadInt32();
            Pointer += 4;

            int ReadDataHash = ReadInt32();
            this.Pointer = OldPointer;

            return (ReadDataHash == CalculatedDataHash && ReadLengthHash == CalculatedLengthHash);
        }

        #region Read Methods

        public byte ReadByte()
        {
            return this.MemoryReader.ReadByte();
        }

        public byte[] ReadBytes(int Count)
        {
            return this.MemoryReader.ReadBytes(Count);
        }

        public short ReadInt16()
        {
            return this.MemoryReader.ReadInt16();
        }

        public int ReadInt32()
        {
            return this.MemoryReader.ReadInt32();
        }

        public long ReadInt64()
        {
            return this.MemoryReader.ReadInt64();
        }

        public string ReadString()
        {
            int Length = this.ReadInt32();
            byte[] StringBytes = this.MemoryReader.ReadBytes(Length);
            string Return = "";

            for (int i = 0; i < Length; i++)
            {
                Return += (char)StringBytes[i];
            }

            return Return;
        }

        public float ReadFloat()
        {
            return this.MemoryReader.ReadSingle();
        }

        public bool ReadBoolean()
        {
            return this.MemoryReader.ReadBoolean();
        }

        #endregion

        #endregion
    }
}
